#include "AReVi/arSystem.h"

using namespace AReVi;

#include "AReVi/activity.h"

#include "AReVi/Lib3D/viewer3D.h"
#include "AReVi/Lib3D/simpleInteractor.h"
#include "AReVi/Lib3D/scene3D.h"
#include "AReVi/Lib3D/object3D.h"
#include "AReVi/Lib3D/light3D.h"
#include "AReVi/Lib3D/boundingBox3D.h"
#include "AReVi/Lib3D/transform3D.h"
#include "AReVi/Lib3D/transform2D.h"
#include "AReVi/Lib3D/material3D.h"
#include "AReVi/Lib3D/urlTexture.h"
#include "AReVi/Shapes/shape3D.h"
#include "AReVi/Shapes/box3D.h"
#include "AReVi/Shapes/mesh3D.h"
#include "AReVi/VRML/vrmlShape3D.h"


//----------------------------------------------------------------------------

class Building : public Shape3D {
public:
  AR_CLASS(Building)
  AR_CONSTRUCTOR(Building)

  virtual
  bool
  setSize(double sx, double sy, double sz);

  virtual
  void
  getSize(double & sx, double & sy, double & sz);

  virtual
  bool
  setFacadeHeight(double fh);

  virtual
  double
  getFacadeHeight(void);

  virtual
  bool
  setSideWalkGeometry(double width, double heigth);

  virtual
  void
  getSideWalkGeometry(double & width, double & heigth);

protected :

  void
  _computeSideWalk(void);

  void
  _computeBuilding(void);

//   void
//   _rebuildIfNeeded(void);

  ArRef<Mesh3D> _sideWalk;
  ArRef<Mesh3D> _facade;
  ArRef<Mesh3D> _windows;
  ArRef<Mesh3D> _roof;

  double _sx,_sy,_sz;

  double _fh;

  double _swHeigth, _swWidth;

};

//----------------------------------------------------------------------------

AR_CLASS_DEF(Building,Shape3D)

//----------------------------------------------------------------------------

Building::Building(ArCW & arCW):
Shape3D(arCW),
  _sideWalk(Mesh3D::NEW()),
  _facade(Mesh3D::NEW()),
  _windows(Mesh3D::NEW()),
  _roof(Mesh3D::NEW()),
  _sx(1.0),
  _sy(1.0),
  _sz(1.0),
  _fh(10.0),
  _swHeigth(1.0),
  _swWidth(1.0)
{
  _computeSideWalk();
  _computeBuilding();

  addRootPart(_sideWalk);
  addRootPart(_facade);
  addRootPart(_windows);
  addRootPart(_roof);
}

Building::~Building() {}

//----------------------------------------------------------------------------

bool
Building::setSideWalkGeometry(double width, double heigth){
  if(width>=0.0 && heigth >= 0.0) {
    _swWidth = width;
    _swHeigth = heigth;
    _computeSideWalk();
    return true;
  }
  else return false;
}

void
Building::getSideWalkGeometry(double & width, double & heigth){
  width = _swWidth;
  heigth = _swHeigth;
}

//----------------------------------------------------------------------------

bool
Building::setSize(double sx, double sy, double sz) {
  if(sx >0.0 && sy > 0.0 && sz > 0.0){
    _sx = sx;
    _sy = sy;
    _sz = sz;
    _computeSideWalk();
    _computeBuilding();

    return true;
  }
  else return false;
}

void
Building::getSize(double & sx, double & sy, double & sz) {
  sx = _sx;
  sy = _sy;
  sz = _sz;
}

bool
Building::setFacadeHeight(double fh) {
  if(fh > 0.0 && fh < _sz) {
    _fh = fh;
    _computeBuilding();

    return true;
  }
  else return false;
}

double
Building::getFacadeHeight(void) {
  return _fh;
}

//----------------------------------------------------------------------------

void
Building::_computeSideWalk(void) {

  _sideWalk->accessVertices().clear();

  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),0));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),0));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),(_sy/2.0+_swWidth),0));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),(_sy/2.0+_swWidth),0));

  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),_swHeigth));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),-(_sy/2.0+_swWidth),_swHeigth));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3((_sx/2.0+_swWidth),(_sy/2.0+_swWidth),_swHeigth));
  _sideWalk->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0+_swWidth),(_sy/2.0+_swWidth),_swHeigth));


  _sideWalk->accessVertexFaces().clear();
  _sideWalk->accessTextureFaces().clear();

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(0,1,5));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(0,5,4));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(1,2,6));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(1,6,5));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(2,3,7));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(2,7,6));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(3,0,4));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(3,4,7));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(5,6,7));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _sideWalk->accessVertexFaces().push_back(Util3D::Face(5,7,4));
  _sideWalk->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _sideWalk->accessTextures().clear();

  _sideWalk->accessTextures().push_back(Util3D::Dbl2(0.0,0.0));
  _sideWalk->accessTextures().push_back(Util3D::Dbl2(1.0,0.0));
  _sideWalk->accessTextures().push_back(Util3D::Dbl2(1.0,1.0));
  _sideWalk->accessTextures().push_back(Util3D::Dbl2(0.0,1.0));

  _sideWalk->computeDefaultNormals(false);

  _sideWalk->applyChanges(false);

  ArRef<Transform2D> tr = Transform2D::NEW();
  tr->preScale((_sy/2.0+_swWidth)/5.0,(_sx/2.0+_swWidth)/5.0);
  _sideWalk->writeTextureTransformation(tr);
  _sideWalk->setTexture(URLTexture::NEW("./Datas/textures/cement_002.jpg",true,true));

}

void
Building::_computeBuilding(void) {
  _facade->accessVertices().clear();

  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),0));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),0));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),0));
  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),0));

  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_fh));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_fh));
  _facade->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_fh));
  _facade->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_fh));


  _facade->accessVertexFaces().clear();
  _facade->accessTextureFaces().clear();

  _facade->accessVertexFaces().push_back(Util3D::Face(0,1,5));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(0,5,4));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessVertexFaces().push_back(Util3D::Face(1,2,6));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(1,6,5));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessVertexFaces().push_back(Util3D::Face(2,3,7));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(2,7,6));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessVertexFaces().push_back(Util3D::Face(3,0,4));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _facade->accessVertexFaces().push_back(Util3D::Face(3,4,7));
  _facade->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _facade->accessTextures().clear();

  _facade->accessTextures().push_back(Util3D::Dbl2(0.0,0.0));
  _facade->accessTextures().push_back(Util3D::Dbl2(1.0,0.0));
  _facade->accessTextures().push_back(Util3D::Dbl2(1.0,1.0));
  _facade->accessTextures().push_back(Util3D::Dbl2(0.0,1.0));


  _facade->computeDefaultNormals(false);

  _facade->applyChanges(false);

  ArRef<Transform2D> tr = Transform2D::NEW();
  tr->preScale( (_sx+_sy)/(2.0*50.0),1);
  _facade->writeTextureTransformation(tr);
  _facade->setTexture(URLTexture::NEW("./Datas/textures/facade.jpg",true,true));


  _windows->accessVertices().clear();

  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_fh));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_fh));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_fh));
  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_fh));

  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_sz));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_sz));
  _windows->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_sz));
  _windows->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_sz));


  _windows->accessVertexFaces().clear();
  _windows->accessTextureFaces().clear();

  _windows->accessVertexFaces().push_back(Util3D::Face(0,1,5));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(0,5,4));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessVertexFaces().push_back(Util3D::Face(1,2,6));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(1,6,5));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessVertexFaces().push_back(Util3D::Face(2,3,7));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(2,7,6));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessVertexFaces().push_back(Util3D::Face(3,0,4));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,1,2));

  _windows->accessVertexFaces().push_back(Util3D::Face(3,4,7));
  _windows->accessTextureFaces().push_back(Util3D::Face(0,2,3));

  _windows->accessTextures().clear();

  _windows->accessTextures().push_back(Util3D::Dbl2(0.0,0.0));
  _windows->accessTextures().push_back(Util3D::Dbl2(1.0,0.0));
  _windows->accessTextures().push_back(Util3D::Dbl2(1.0,1.0));
  _windows->accessTextures().push_back(Util3D::Dbl2(0.0,1.0));

  _windows->computeDefaultNormals(false);

  _windows->applyChanges(false);

  ArRef<Transform2D> tr2 = Transform2D::NEW();
  tr2->preScale((_sx + _sy + 2.0*_swWidth )/(2.0*50.0),(_sz-_fh)/10.0);
  _windows->writeTextureTransformation(tr2);
  _windows->setTexture(URLTexture::NEW("./Datas/textures/windows.jpg",true,true));

  _roof->accessVertices().clear();

  _roof->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),-(_sy/2.0),_sz));
  _roof->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),-(_sy/2.0),_sz));
  _roof->accessVertices().push_back(Util3D::Dbl3((_sx/2.0),(_sy/2.0),_sz));
  _roof->accessVertices().push_back(Util3D::Dbl3(-(_sx/2.0),(_sy/2.0),_sz));


  _roof->accessVertexFaces().clear();
  _roof->accessTextureFaces().clear();

  _roof->accessVertexFaces().clear();

  _roof->accessVertexFaces().push_back(Util3D::Face(0,1,2));
  _roof->accessVertexFaces().push_back(Util3D::Face(0,2,3));

  _roof->computeDefaultNormals(false);

  _roof->applyChanges(false);

}

//----------------------------------------------------------------------------

class Square : public ArObject{
public:
  AR_CLASS(Square)
  AR_CONSTRUCTOR(Square)
  AR_CONSTRUCTOR_4(Square, double, posX,
                           double, posY,
                           double, sizeX,
                           double, sizeY)


  pair<ArRef<Square>, ArRef<Square> >
  divide(double widthBetween, double minWidth);

  double pos[2];
  double size[2];
};

//----------------------------------------------------------------------------

AR_CLASS_DEF(Square,ArObject)

//----------------------------------------------------------------------------

Square::Square(ArCW & arCW):
ArObject(arCW)
{
  pos[0] = 0.0; // X
  pos[1] = 0.0; // Y
  size[0] = 0.0; // X
  size[1] = 0.0; // Y
}

Square::Square(ArCW & arCW, double posX,
                            double posY,
                            double sizeX,
                            double sizeY):
ArObject(arCW){
  pos[0] = posX;
  pos[1] = posY;
  size[0] = sizeX;
  size[1]= sizeY;
}

Square::~Square(void) {}

//----------------------------------------------------------------------------

pair<ArRef<Square>, ArRef<Square> >
Square::divide(double widthBetween, double minWidth) {
  pair<ArRef<Square>, ArRef<Square> > result;

  // random draw between x and y division
  int xy = ArSystem::integerRand(2);

  if(size[xy] < 2.0*minWidth+widthBetween || size[xy]/size[1-xy] < 0.9) {
    result.first = Square::nullRef();
    result.second = Square::nullRef();
  } else {
    double roadCoord = minWidth+0.5*widthBetween +
      ArSystem::realRand()*(size[xy] - (2.0*minWidth + widthBetween));

    double firstSize[2];
    double firstPos[2];

    double secondSize[2];
    double secondPos[2];

    // size don't change on the other coordinate
    firstSize[1-xy] = size[1-xy];
    secondSize[1-xy] = size[1-xy];

    firstSize[xy] = roadCoord - 0.5 * widthBetween;
    secondSize[xy] = size[xy]-roadCoord - 0.5 * widthBetween;

    // pos don't change on the other coordinate
    firstPos[1-xy] = pos[1-xy];
    secondPos[1-xy] = pos[1-xy];

    firstPos[xy] = pos[xy] - (size[xy]/2.0) + firstSize[xy] / 2.0;
    secondPos[xy] = pos[xy] - (size[xy]/2.0) + firstSize[xy] +
      widthBetween + secondSize[xy] / 2.0 ;

    ArRef<Square> first = Square::NEW(firstPos[0],firstPos[1],firstSize[0],firstSize[1]);
    ArRef<Square> second = Square::NEW(secondPos[0], secondPos[1], secondSize[0], secondSize[1]);

    result = make_pair<ArRef<Square>, ArRef<Square> >(first,second);

  }

  return result;
}

//----------------------------------------------------------------------------

class CityGenerator : public ArObject
{
public:
  AR_CLASS(CityGenerator)
  AR_CONSTRUCTOR(CityGenerator)

  bool
  buildCity(double sizeX,
            double sizeY,
            double maxSlenderness,
            double roadWidth,
            double sideWalkwidth,
            double buildingMinWidth,
            unsigned int nbBuildings);

  const StlVector<ArRef<Object3D> >&
  getBuildings(void);

  ArRef<Object3D>
  getRoad(void);

protected:

  void
  _computeBuildings(StlVector<ArRef<Square> > squares, 
                    double maxSlenderness,
                    double sideWalkWidth);

  StlVector<ArRef<Object3D> > _buildings;

  ArRef<Object3D> _road;
};

//----------------------------------------------------------------------------

AR_CLASS_DEF(CityGenerator,ArObject)

//----------------------------------------------------------------------------

CityGenerator::CityGenerator(ArCW & arCW):
ArObject(arCW)
{
}

CityGenerator::~CityGenerator(){}

//----------------------------------------------------------------------------

bool
CityGenerator::buildCity(double sizeX,
                         double sizeY,
                         double maxSlenderness,
                         double roadwidth,
                         double sideWalkwidth,
                         double buildingMinWidth,
                         unsigned int nbbuildings) {
  StlVector<ArRef<Square> > squares;

  ArRef<Square> base = Square::NEW(0.0,0.0,sizeX,sizeY);
  squares.push_back(base);

  for(unsigned int i=1; i< nbbuildings ; i++){

    // draw a random square
    StlVector<ArRef<Square> >::iterator randSquareIt;

    if(squares.size() == 0 ){
      cerr << "ERROR : no more squares to divide !" << endl;
      return false;
    }
    else if(squares.size() > 1){
      randSquareIt = squares.begin()+ArSystem::integerRand(squares.size()-1);
    }
    else{
      randSquareIt = squares.begin();
    }

    // divide this square
    pair<ArRef<Square>, ArRef<Square> > newSquares =
      (*randSquareIt)->divide(roadwidth+2.0*sideWalkwidth,buildingMinWidth);

    if(newSquares.first) { // divide success
      squares.erase(randSquareIt);

      squares.push_back(newSquares.first);
      squares.push_back(newSquares.second);
    }
    else
      i -- ; // same player try again ;)

  }

  _computeBuildings(squares, maxSlenderness, sideWalkwidth);

  _road = Object3D::NEW();
  ArRef<Shape3D> sh = Shape3D::NEW();
  ArRef<Box3D> mesh = Box3D::NEW();
  ArRef<Transform2D> tr = Transform2D::NEW();
  tr->preScale(sizeX/4.0,sizeY/4.0);
  mesh->writeTextureTransformation(tr);
  mesh->setTexture(URLTexture::NEW("Datas/textures/road.jpg",true,true));
  mesh->setSize(sizeX,sizeY,0.1);
  sh->addRootPart(mesh);
  _road->setShape(sh);

  return true;
}

//----------------------------------------------------------------------------

void
CityGenerator::_computeBuildings(StlVector<ArRef<Square> > squares,
                                 double maxSlenderness,
                                 double sideWalkWidth) {
  for(unsigned int i =0 ; i < squares.size() ; i++) {
    ArRef<Object3D> obj = Object3D::NEW();
    ArRef<Building> sh = Building::NEW();

    double H = sqrt(squares[i]->size[0]*squares[i]->size[1]) / maxSlenderness;

    if(H > 2.0*fmax( squares[i]->size[0], squares[i]->size[1])) 
    	H = 2.0*fmax( squares[i]->size[0], squares[i]->size[1]);

    sh->setSize(squares[i]->size[0],squares[i]->size[1],H);
    sh->setSideWalkGeometry(sideWalkWidth,0.5);
    sh->setFacadeHeight(15.0);

    obj->setShape(sh);
    obj->setPosition(squares[i]->pos[0],squares[i]->pos[1],0.0);

    _buildings.push_back(obj);
  }

}

//----------------------------------------------------------------------------

const StlVector<ArRef<Object3D> >&
CityGenerator::getBuildings(void) {
 return _buildings;
}

//----------------------------------------------------------------------------

ArRef<Object3D>
CityGenerator::getRoad(void) {
 return _road;
}

//----------------------------------------------------------------------------

class MyViewer : public Viewer3D
{
public:
  AR_CLASS(MyViewer)
  AR_CONSTRUCTOR(MyViewer)

  virtual void keyboardCB(const Renderer3D::KeyboardEvent & evt);
  virtual void mouseButtonCB(const Renderer3D::MouseButtonEvent & evt);
  virtual void mouseMotionCB(const Renderer3D::MouseMotionEvent & evt);
  virtual void motionCB(const Window3D::MotionEvent & evt);

protected:

  ArRef<SimpleInteractor> _interactor;
  ArRef<Scene3D> _scene;

};

//---------------------------------------------------------------------------

AR_CLASS_DEF(MyViewer,Viewer3D)

void
MyViewer::keyboardCB(const Renderer3D::KeyboardEvent & evt)
{
cerr << "Keyboard  "
     << evt.source->getAlias()
     << "  KEY:" << evt.key
     << "  PRESSED:" << evt.pressed
     << "  X:" << evt.xMouse
     << "  Y:" << evt.yMouse << endl;
if(!evt.pressed)
  {
  return;
  }
}

void
MyViewer::mouseButtonCB(const Renderer3D::MouseButtonEvent & evt)
{
cerr << "MouseButton  "
     << evt.source->getAlias()
     << "  BTN:" << evt.button
     << "  P:" << evt.pressed
     << "  X:" << evt.xMouse
     << "  Y:" << evt.yMouse << endl;
}

void
MyViewer::mouseMotionCB(const Renderer3D::MouseMotionEvent & evt)
{
cerr << "MouseMotion  "
     << evt.source->getAlias()
     << "  X:" << evt.xMouse
     << "  Y:" << evt.yMouse << endl;
}

void
MyViewer::motionCB(const Base3D::MotionEvent & evt)
{
cerr << "Motion  "
     << evt.source->getAlias() << endl;
}

//----------------------------------------------------------------------------

MyViewer::MyViewer(ArCW & arCW)
: Viewer3D(arCW),
  _interactor(SimpleInteractor::NEW()),
  _scene(Scene3D::NEW())
{
  selectScene(_scene);
  _interactor->setRenderer(thisRef());
  setFarDistance(10000.0);
  _interactor->setLinearSpeed(20.0);

  translate(0.0,0.0,15.0);

  if(ArSystem::getCommandLine().size() == 8){

    ArRef<CityGenerator> cityGen = CityGenerator::NEW();
    cityGen->setTransient(false);

    double sizeX,sizeY,maxSlenderness,roadWidth,sideWalkWidth;
    double buildingMinWidth;
    int nbBuildings;

    if(strToDouble(sizeX,ArSystem::getCommandLine()[1]) &&
       strToDouble(sizeY,ArSystem::getCommandLine()[2]) &&
       strToDouble(maxSlenderness,ArSystem::getCommandLine()[3]) &&
       strToDouble(roadWidth,ArSystem::getCommandLine()[4]) &&
       strToDouble(sideWalkWidth,ArSystem::getCommandLine()[5]) &&
       strToDouble(buildingMinWidth,ArSystem::getCommandLine()[6]) &&
       strToInt(nbBuildings,ArSystem::getCommandLine()[7])) {

      cityGen->buildCity(sizeX,sizeY,maxSlenderness,roadWidth,sideWalkWidth,
                         buildingMinWidth, nbBuildings);

      for(unsigned int i =0;i < cityGen->getBuildings().size() ; i++) {
        _scene->addObject(cityGen->getBuildings()[i]);
        cityGen->getBuildings()[i]->setMouseButtonInteraction(false);
        cityGen->getBuildings()[i]->setMotionInteraction(false);
      }

      _scene->addObject(cityGen->getRoad());
      cityGen->getRoad()->setMouseButtonInteraction(false);
      cityGen->getRoad()->setMotionInteraction(false);

      return;
    }
  }

  cerr << "usage : ./cityGen sizeX sizeY maxSlenderness roadWidth "
       << "sideWalkWidth buildingMinWidth nbBuildings"<< endl;
  ArSystem::leaveSimulation();

}

MyViewer::~MyViewer(void)
{
}

//----------------------------------------------------------------------------

ArRef<Scheduler>
simulationInit(void)
{
ArRef<Scheduler> sched=RealTimeScheduler::NEW(1e-3);

 ArRef<Viewer3D> v=MyViewer::NEW();
 v->setCloseAction(Renderer3D::CLOSE_LEAVE);
 unsigned int w,h;
 Renderer3D::getScreenSize(w,h);
 v->setWindowGeometry(0,0,w/2,h-1);
 v->setMapped(true);
 v->setTransient(false);

return(sched);
}

int
main(int argc,
     char ** argv)
{
ArSystem arevi(argc,argv);

 MyViewer::REGISTER_CLASS();
 CityGenerator::REGISTER_CLASS();
 Square::REGISTER_CLASS();
 Building::REGISTER_CLASS();

ArSystem::loadPlugin("Imlib2ImageLoader");
ArSystem::loadPlugin("MagickImageLoader");
ArSystem::simulationLoop(&simulationInit);
return(0);
}

//----------------------------------------------------------------------------
